package com.trs.publish.aspect;

import java.lang.reflect.Method;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import com.google.gson.Gson;
import com.trs.publish.Constants.MyConstants;
import com.trs.publish.domain.OperationLog;
import com.trs.publish.domain.User;

/**
 * @author jiahaihong
 *
 */
@Aspect
@Component
public class OperationAspect {
	
	
	private static final  Logger logger = LoggerFactory.getLogger(OperationAspect.class);

	 /** 
     * Pointcut 
     * 定义Pointcut，Pointcut的名称为annotationPointCut()，此方法没有返回值和参数 
     * 该方法就是一个标识，不进行调用 
     */ 
	@Pointcut("@annotation(com.trs.publish.aspect.OperationDesc)")
	public void annotationPointCut() {}
	
	@Before("annotationPointCut()")
    public void doBefore(JoinPoint joinPoint){
       MethodSignature sign =  (MethodSignature)joinPoint.getSignature();
       Method method = sign.getMethod();
       logger.info("接受方法的"+method.getName()+"前置日志");
    }
	
	@After(value = "annotationPointCut()")    
	public void afterAdvice(JoinPoint joinPoint) throws ClassNotFoundException {
	    	String methodDescription = getControllerMethodDescription(joinPoint);
	    	//涉及数据库增删改的操作需要保留操作日志
	    	//0_描述：涉及数据库变化
	    	//1_描述：不涉及
	    	if(!StringUtils.isEmpty(methodDescription) && methodDescription.startsWith("0_")){
	    		ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
	       	 	HttpServletRequest request = sra.getRequest();
	            HttpSession session = request.getSession();  
	            //读取session中的用户  
	            User user = (User) session.getAttribute("user");  
	            //请求的IP  
	            OperationLog log = new OperationLog();
	            log.setUserid(user.getId());
	            log.setUsername(user.getUsername());
	            log.setTruename(user.getTruename());
	            log.setSfzh(user.getSfzh());
	            log.setIp(request.getRemoteAddr());
	            log.setDepartment(user.getDepartment());
	            String methodName = joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()";
	            log.setMethodname(methodName);
	            log.setMethoddescription(methodDescription.substring(2));
	            log.setUri(request.getRequestURI());
	            //获取用户请求方法的参数并序列化为JSON格式字符串  
	            String params = "";  
	            Gson gson = new Gson();
	            if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {  
	            	params = gson.toJson(joinPoint.getArgs());
	            }
	            log.setMethodparams(params);
	            MyConstants.operationLogQueue.offer(log);
	    	}
	    }   
	    
	    /** 
	     * 获取注解中对方法的描述信息 用于Controller层注解 
	     * 
	     * @param joinPoint 切点 
	     * @return 方法描述 
	     * @throws ClassNotFoundException 
	     * @throws Exception 
	     */  
	    public static String getControllerMethodDescription(JoinPoint joinPoint) throws ClassNotFoundException{  
	        String targetName = joinPoint.getTarget().getClass().getName();  
	        String methodName = joinPoint.getSignature().getName();  
	        Object[] arguments = joinPoint.getArgs();  
	        Class targetClass = Class.forName(targetName);  
	        Method[] methods = targetClass.getMethods();  
	        String description = "";  
	        for (Method method : methods) {  
	            if (method.getName().equals(methodName)) {  
	                Class[] clazzs = method.getParameterTypes();  
	                if (clazzs.length == arguments.length) {  
	                    description = method.getAnnotation(OperationDesc.class).description();  
	                    break;  
	                }  
	            }  
	        }  
	        return description;  
	    }
    
}
